/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {
  diffArrays, diffChars, diffCss, diffJson, diffLines, diffSentences, diffTrimmedLines, diffWords, diffWordsWithSpace, createPatch, applyPatch, applyPatches, createTwoFilesPatch, structuredPatch, parsePatch, convertChangesToXML, convertChangesToDMP, canonicalize, merge
} from './jsDiff/lib/index.es6.js'
import { source1, source2 } from './source.js';


function diffChars_Test() {
  let diff = [];
  let startTime = Date.now();
  diff = diffChars(source1, source2);
  let endTime = Date.now();
  if (diff.length <= 0) {
    throw 'diffChars error'
  }
  print(`jsDiff_diffChars: ${endTime - startTime} ms`)
}



function diffWords_Test() {
  let diff = [];
  let startTime = Date.now();
  diff = diffWords(source1, source2);
  let endTime = Date.now();
  if (diff.length <= 0) {
    throw 'diffWords error'
  }
  print(`jsDiff_diffWords: ${endTime - startTime} ms`)
}





function diffWordsWithSpace_Test() {
  let diff = [];
  let startTime = Date.now();
  diff = diffWordsWithSpace(source1, source2);
  let endTime = Date.now();
  if (diff.length <= 0) {
    throw 'diffWordsWithSpace error'
  }
  print(`jsDiff_diffWordsWithSpace: ${endTime - startTime} ms`)
}



function diffLines_Test() {
  let diff = [];
  let startTime = Date.now();
  for (let i = 0; i < 1000; i++) {
    diff = diffLines(source1, source2);
  }
  let endTime = Date.now();
  if (diff.length <= 0) {
    throw 'diffLines error'
  }
  print(`jsDiff_diffLines: ${endTime - startTime} ms`)
}



function diffTrimmedLines_Test() {
  let diff = [];
  let startTime = Date.now();
  for (let i = 0; i < 1000; i++) {
    diff = diffTrimmedLines(source1, source2)
  }
  let endTime = Date.now();
  if (diff.length <= 0) {
    throw 'diffTrimmedLines error'
  }
  print(`jsDiff_diffTrimmedLines: ${endTime - startTime} ms`)
}



function diffSentences_Test() {
  let diff = [];
  let startTime = Date.now();
  for (let i = 0; i < 1000; i++) {
    diff = diffSentences(source1, source2);
  }
  let endTime = Date.now();
  if (diff.length <= 0) {
    throw 'diffSentences error'
  }
  print(`jsDiff_diffSentences: ${endTime - startTime} ms`)
}



function diffCss_Test() {
  const one = `
  .example {
    width: 960px;
    padding: 0;
    margin: 10px;
    background-color: #f2f2f2;
    border: 1px solid #ccc;
    font-family: Arial, sans-serif;
    font-size: 16px;
    color: #333;
    text-align: center;
    line-height: 1.5;
    box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1);
    display: block;
    position: relative;
    top: 0;
    left: 0;
    z-index: 1;
    transition: all 0.3s ease-in-out;
    border-radius: 5px;
    text-transform: uppercase;
    text-decoration: none;
    overflow: hidden;
    cursor: pointer;
  }
  `;
  const other = `
  .custom-style {
    width: 800px;
    height: 400px;
    padding: 20px;
    margin: 10px;
    background-color: #f8f8f8;
    border: 2px solid #ccc;
    font-family: "Helvetica Neue", Arial, sans-serif;
    font-size: 14px;
    color: #666;
    text-align: left;
    line-height: 1.6;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    display: inline-block;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 2;
    transition: all 0.4s ease;
    border-radius: 8px;
    text-transform: capitalize;
    text-decoration: none;
    overflow: auto;
    cursor: pointer;
  }
  `;
  let diff = [];
  let startTime = Date.now();
  for (let i = 0; i < 100; i++) {
    diff = diffCss(one, other);
  }
  let endTime = Date.now();
  if (diff.length <= 0) {
    throw 'diffChars error'
  }
  print(`jsDiff_diffCss: ${endTime - startTime} ms`)
}



function diffJson_Test() {
  const one =
  {
    "name": "Alice",
    "age": 25,
    "gender": "female",
    "city": "New York",
    "country": "USA",
    "email": "alice@example.com",
    "phone": "123-456-7890",
    "hobbies": ["reading", "traveling", "painting"],
    "education": {
      "degree": "Bachelor's",
      "major": "Computer Science",
      "graduation_year": 2020
    },
    "work_experience": [
      {
        "company": "Tech Inc.",
        "position": "Software Engineer",
        "years_worked": 3
      },
      {
        "company": "Data Co.",
        "position": "Data Analyst",
        "years_worked": 2
      }
    ]
  }
    ;
  const other =
  {
    "name": "Alice",
    "age": 25,
    "gender": "female",
    "city": "New York",
    "country": "USA",
    "email": "alice@example.com",
    "phone": "123-456-7890",
    "hobbies": ["reading", "traveling", "painting"],
    "education": {
      "degree": "Bachelor's",
      "major": "Computer Science",
      "graduation_year": 2020
    },
    "work_experience": [
      {
        "company": "Tech Inc.",
        "position": "Software Engineer",
        "years_worked": 3
      },
      {
        "company": "Data Co.",
        "position": "Data Analyst",
        "years_worked": 2
      }
    ],
    "relationship_status": "Single",
    "languages": ["English", "Spanish"],
    "skills": ["Java", "Python", "SQL"],
    "certifications": ["AWS Certified Developer", "Scrum Master"],
    "interests": ["Photography", "Yoga"],
    "address": {
      "street": "123 Main St",
      "city": "New York",
      "zipcode": "10001"
    }
  }
    ;
  let diff = [];
  let startTime = Date.now();
  for (let i = 0; i < 100; i++) {
    diff = diffJson(one, other);
  }
  let endTime = Date.now();
  if (diff.length <= 0) {
    throw 'diffChars error'
  }
  print(`jsDiff_diffJson: ${endTime - startTime} ms`)

}



function diffArrays_Test() {
  const one = ["apple", "banana", "orange", "rabbit", "watermelon", "kiwi", "dog", "blueberry", "mango", "parrot", "peach", "pear", "turtle", "cherry", "apricot", "lemon", "lime", "coconut", "pomegranate", "fig", "raspberry", "blackberry", "cranberry", "elderberry", "guava", "papaya", "lychee", "nectarine", "tangerine", "cantaloupe", "honeydew", "persimmon", "dragonfruit", "jackfruit", "starfruit", "passion fruit", "mulberry", "boysenberry", "kiwifruit", "carambola", "quince", "durian", "rhubarb", "plantain", "date", "acai berry", "breadfruit", "kumquat", "soursop"];
  const other = ["cat", "dog", "rabbit", "hamster", "guinea pig", "ferret", "parrot", "canary", "goldfish", "turtle", "frog", "chinchilla", "hedgehog", "gerbil", "mouse", "rat", "snake", "lizard", "gecko", "iguana", "tarantula", "scorpion", "hermit crab", "axolotl", "salamander", "newt", "tortoise", "iguana", "armadillo", "kangaroo", "koala", "wombat", "wallaby", "platypus", "echidna", "kookaburra", "cockatoo", "emu", "dingo", "quokka", "numbat", "tasmanian devil", "cassowary", "dingo", "bandicoot", "possum", "quoll", "sugar glider", "bilby", "flying fox", "dugong", "seahorse", "manatee"];
  let diff = [];
  let startTime = Date.now();
  for (let i = 0; i < 100; i++) {
    diff = diffArrays(one, other);
  }
  let endTime = Date.now();
  if (diff.length <= 0) {
    throw 'diffChars error'
  }
  print(`jsDiff_diffArrays: ${endTime - startTime} ms`)
}



const oldFileName = 'oldFileName';
const newfileName = 'newFileName';
const oldStr = 'Hello, this is the original text.';
const newStr = 'Hello, this is the updated text.';
const oldHeader = 'header1';
const newHeader = 'header2';

function createPatch_Test() {
  let result = '';
  let startTime = Date.now();
  for (let i = 0; i < 10000; i++) {
    result = createPatch(oldFileName, oldStr, newStr, oldHeader, newHeader);
  }
  let endTime = Date.now();
  const newResult = applyPatch(oldStr, result)
  if (newResult != newStr) {
    throw 'createPatch error'
  }
  print(`jsDiff_createPatch: ${endTime - startTime} ms`)
}



function createTwoFilesPatch_Test() {
  let result = '';
  let startTime = Date.now();
  for (let i = 0; i < 10000; i++) {
    result = createTwoFilesPatch(oldFileName, newfileName, oldStr, newStr, oldHeader, newHeader);
  }
  let endTime = Date.now();
  const newResult = applyPatch(oldStr, result)
  if (newResult != newStr) {
    throw 'createTwoFilesPatch error'
  }
  print(`jsDiff_createTwoFilesPatch: ${endTime - startTime} ms`)
}



function structuredPatch_Test() {
  let result = null;
  let startTime = Date.now();
  for (let i = 0; i < 10000; i++) {
    result = structuredPatch(oldFileName, newfileName, oldStr, newStr);
  }
  let endTime = Date.now();
  if (result.newFileName != newfileName) {
    throw 'structuredPatch error'
  }
  print(`jsDiff_structuredPatch: ${endTime - startTime} ms`)
}



function parsePatch_Test() {
  const patch = createPatch(oldFileName, oldStr, newStr, oldHeader, newHeader)
  let result = [];
  let startTime = Date.now();
  for (let i = 0; i < 10000; i++) {
    result = parsePatch(patch);
  }
  let endTime = Date.now();
  const newResult = applyPatch(oldStr, result)
  if (newResult != newStr) {
    throw 'parsePatch error'
  }
  print(`jsDiff_parsePatch: ${endTime - startTime} ms`)
}



function convertChangesToXML_Test() {
  const diffResult = diffChars('New Value.', 'New ValueMoreData.');
  let result = '';
  let startTime = Date.now();
  for (let i = 0; i < 10000; i++) {
    result = convertChangesToXML(diffResult);
  }
  let endTime = Date.now();
  if (result.length <= 0) {
    throw 'convertChangesToXML error'
  }
  print(`jsDiff_convertChangesToXML: ${endTime - startTime} ms`)
}



function convertChangesToDMP_Test() {
  const diffResult = diffChars('New Value.', 'New ValueMoreData.');
  let result = [];
  let startTime = Date.now();
  for (let i = 0; i < 10000; i++) {
    result = convertChangesToDMP(diffResult);
  }
  let endTime = Date.now();
  if (result.length <= 0) {
    throw 'convertChangesToDMP error'
  }
  print(`jsDiff_convertChangesToDMP: ${endTime - startTime} ms`)
}

function canonicalize_Test() {
  let param = {
    d: 101112, c: 789, a: '123', b: 456
  }
  let result = {};
  let startTime = Date.now();
  for (let i = 0; i < 10000; i++) {
    result = canonicalize(param);
  }
  let endTime = Date.now();
  if (result.d != 101112) {
    throw 'canonicalize error'
  }
  print(`jsDiff_canonicalize: ${endTime - startTime} ms`)
}



const mine =
  'Index: test\n'
  + '===================================================================\n'
  + '--- test\theader1\n'
  + '+++ test\theader2\n'
  + '@@ -1,3 +1,4 @@\n'
  + ' line2\n'
  + ' line3\n'
  + '+line4\n'
  + ' line5\n';
const theirs =
  'Index: test\n'
  + '===================================================================\n'
  + '--- test\theader1\n'
  + '+++ test\theader2\n'
  + '@@ -25,3 +25,4 @@\n'
  + ' foo2\n'
  + ' foo3\n'
  + '+foo4\n'
  + ' foo5\n';

function merge_Test() {
  let result = {};
  let startTime = Date.now();
  for (let i = 0; i < 10000; i++) {
    result = merge(mine, theirs);
  }
  let endTime = Date.now();
  if (result.hunks.length != 2) {
    throw 'merge error'
  }
  print(`jsDiff_merge: ${endTime - startTime} ms`)
}



function applyPatch_Test() {
  const patch = parsePatch(
    'Index: test\n'
    + '===================================================================\n'
    + '--- test\theader1\n'
    + '+++ test\theader2\n'
    + '@@ -1,3 +1,4 @@\n'
    + ' line2\n'
    + ' line3\n'
    + '+line4\n'
    + ' line5\n');

  let result = '';
  let startTime = Date.now();
  for (let i = 0; i < 10000; i++) {
    result = applyPatch(
      'line2\n'
      + 'line3\n'
      + 'line5\n',
      patch[0]);
  }
  let endTime = Date.now();
  if (!result.includes('line4')) {
    throw 'applyPatch error'
  }
  print(`jsDiff_applyPatch: ${endTime - startTime} ms`)

}




class Data {
  contents = {}
  expected = {}

  loadFile(index, callback) {
    if (index.index !== undefined) {
      callback(undefined, this.contents[index.index]);
    }
  }

  patched(index, content, callback) {
    // if (index.index == 'test') {
    //   this.contents.test = content
    // } else if (index.index == 'test2') {
    //   this.contents.test2 = content
    // }
    callback(undefined);
  }

  complete(err) {
    if (err) {
      throw 'applyPatches error'
    }
  }

  constructor(contents, expected) {
    this.contents = contents;
    this.expected = expected
  }
}

function applyPatches_Test() {
  const patch =
    'Index: test\n'
    + '===================================================================\n'
    + '--- test\theader1\n'
    + '+++ test\theader2\n'
    + '@@ -1,3 +1,4 @@\n'
    + ' line2\n'
    + ' line3\n'
    + '+line4\n'
    + ' line5\n'
    + 'Index: test2\n'
    + '===================================================================\n'
    + '--- test\theader1\n'
    + '+++ test\theader2\n'
    + '@@ -1,3 +1,4 @@\n'
    + ' foo2\n'
    + ' foo3\n'
    + '+foo4\n'
    + ' foo5\n';
  const contents = {
    test:
      'line2\n'
      + 'line3\n'
      + 'line5\n',
    test2:
      'foo2\n'
      + 'foo3\n'
      + 'foo5\n'
  };
  const expected = {
    test:
      'line2\n'
      + 'line3\n'
      + 'line4\n'
      + 'line5\n',
    test2:
      'foo2\n'
      + 'foo3\n'
      + 'foo4\n'
      + 'foo5\n'
  };
  let data = new Data(contents, expected)
  let startTime = Date.now();
  for (let i = 0; i < 10000; i++) {
    applyPatches(patch, data);
  }
  let endTime = Date.now();
  print(`jsDiff_applyPatches: ${endTime - startTime} ms`)
}

diffChars_Test()
diffWords_Test()
diffWordsWithSpace_Test()
diffLines_Test()
diffTrimmedLines_Test()
diffSentences_Test()
diffCss_Test()
diffJson_Test()
diffArrays_Test()
createPatch_Test()
createTwoFilesPatch_Test()
structuredPatch_Test()
parsePatch_Test()
convertChangesToXML_Test()
convertChangesToDMP_Test()
canonicalize_Test()
merge_Test()
applyPatch_Test()
applyPatches_Test()

